package data.complex;

import data.base.Bary3;
import data.base.TextureCoordinate;
import data.base.Vector3;
import data.base.Vertex;


public class Intersection extends Vertex{
  private Triangle triangle;
  private Bary3 bary;
  private Ray ray;
  private boolean intersects = false;
  public static final double ERROR_CONSTANT = 0.00000001;
  
  public Intersection(Ray ray){
    super(0, 0, 0);
    this.ray = ray;
  }
  
  public boolean testTriangleAndPoint(Triangle triangle, Vector3 p){
    Bary3 baryTemp = triangle.getBarycentricCoordinates(p);
    if(isIntersecting(baryTemp)){
      copy(p);
      intersects = true;
      this.triangle = triangle;
      bary = baryTemp;
      return true;
    }
    return false;
  }
  
  @Override
  public TextureCoordinate getTextureCoordinate(){
    if(textureCoordinate == null && triangle.getA().getTextureCoordinate() != null){
      TextureCoordinate txA = triangle.getA().getTextureCoordinate();
      TextureCoordinate txB = triangle.getB().getTextureCoordinate();
      TextureCoordinate txC = triangle.getC().getTextureCoordinate();
      textureCoordinate = new TextureCoordinate(
          txA.getU() * bary.getA() + txB.getU() * bary.getB() + txC.getU() * bary.getC(), 
          txA.getV() * bary.getA() + txB.getV() * bary.getB() + txC.getV() * bary.getC());
    }
    return textureCoordinate;
  }
  
  @Override
  public Vector3 getNormal(){
    Vector3 normalA = triangle.getA().getNormal();
    Vector3 normalB = triangle.getB().getNormal();
    Vector3 normalC = triangle.getC().getNormal();
    if(normalA == null || normalB == null || normalC == null){
      normal = triangle.getNormal(true);
    }
    else{
      normal = new Vector3(
          normalA.getX() * bary.getA() + normalB.getX() * bary.getB() + normalC.getX() * bary.getC(),
          normalA.getY() * bary.getA() + normalB.getY() * bary.getB() + normalC.getY() * bary.getC(),
          normalA.getZ() * bary.getA() + normalB.getZ() * bary.getB() + normalC.getZ() * bary.getC());
      normal.normalize();
    }
    return normal;
  }
    
  private boolean isIntersecting(Bary3 baryTemp){
    return !(baryTemp.getA() < -ERROR_CONSTANT || baryTemp.getB() < -ERROR_CONSTANT || baryTemp.getC() < -ERROR_CONSTANT);
  }
  
  public Ray getRay(){
    return ray;
  }
  
  public Triangle getTriangle(){
    return triangle;
  }
  
  public boolean isIntersecting(){
    return intersects;
  }
}
